package xyz.thoughtset.viewer.modules.step.service;

import cn.zhxu.bs.BeanSearcher;
import cn.zhxu.bs.MapSearcher;
import cn.zhxu.bs.util.MapUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.databind.JavaType;
import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import xyz.thoughtset.viewer.common.crud.core.service.BaseServiceImpl;
import xyz.thoughtset.viewer.modules.step.dao.BlockBodyEleDao;
import xyz.thoughtset.viewer.modules.step.dao.BlockInfoDao;
import xyz.thoughtset.viewer.modules.step.entity.BlockTypeEnum;
import xyz.thoughtset.viewer.modules.step.entity.block.BlockBodyEle;
import xyz.thoughtset.viewer.modules.step.entity.block.BlockInfo;
import xyz.thoughtset.viewer.modules.step.entity.block.EleParam;
import xyz.thoughtset.viewer.modules.step.entity.vo.BodyEleView;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional
public class BlockInfoServiceImpl extends BaseServiceImpl<BlockInfoDao, BlockInfo> implements BlockInfoService {

    @Autowired
    private BlockBodyEleDao blockBodyEleDao;
    @Autowired
    private BeanSearcher beanSearcher;
    private JavaType eleParamType;

    @PostConstruct
    public void init() {
        eleParamType = mapper.getTypeFactory().constructParametricType(List.class, EleParam.class);
    }

    @Override
    public BlockInfo saveData(BlockInfo entity) {
        if (!StringUtils.hasLength(entity.getDataStr())){
            entity.setDataStr("{}");
        }
        if(ObjectUtils.isEmpty(entity.getBodys())){
//            "transpose"
            if (entity.getBodyType().equals(BlockTypeEnum.TRANSPOSE.getType())
                    || entity.getBodyType().equals(BlockTypeEnum.MCP.getType())
                    || entity.getBodyType().equals(BlockTypeEnum.EXECAI.getType())
            ){
                saveOrUpdate(entity);
                return entity;
            }else {
                throw new IllegalArgumentException("Block body elements cannot be empty for block type: " + entity.getBodyType());
            }
        }
        saveOrUpdate(entity);
//        BlockInfo entity = (BlockInfo) super.saveData(baseMap);
        List<BlockBodyEle> oldEles = blockEles(entity.getId());
        HashSet oldEleIds = new HashSet<>();
        int i = 0;
        for (BlockBodyEle ele : entity.getBodys()) {
            ele.setPid(entity.getId());
            ele.setOrderNum(++i);
            blockBodyEleDao.insertOrUpdate(ele);
            oldEleIds.add(ele.getId());
        }
        if (!ObjectUtils.isEmpty(oldEles)){
            List<String> delIds = oldEles.stream()
                    .filter(e->!oldEleIds.contains(e.getId()))
                    .map(BlockBodyEle::getId)
                    .collect(Collectors.toList());
            blockBodyEleDao.deleteByIds(delIds);
        }
        return entity;
    }

    @Override
    public boolean deleteById(String pkey) {
        blockBodyEleDao.delete(this.pidQueryWrapper(pkey));
        return super.deleteById(pkey);
    }

    @Override
    public BlockInfo getById(Serializable id) {
        BlockInfo result = super.getById(id);
        Map<String, Object> params = MapUtils.builder()
                .field(BlockBodyEle::getPid, id)
                .orderBy(BlockBodyEle::getOrderNum).asc()
                .build();
//        List<BodyEleView> bodyEles = beanSearcher.searchList(BodyEleView.class,params);

        QueryWrapper<BlockBodyEle> query = new QueryWrapper();
        query.lambda().eq(BlockBodyEle::getPid,id)
                .orderByAsc(BlockBodyEle::getOrderNum);
        List<BlockBodyEle> bodyEles = blockBodyEleDao.selectList(query);
        result.setBodys(bodyEles);
        return result;
    }

    @Override
    public Object saveBlockOrder(List<String> items) {
        Integer sortNum = 0;
        List<BlockInfo> blocks = new ArrayList<>(items.size());
        for (String item : items){
            blocks.add(BlockInfo.buildByOrder(item,++sortNum,BlockInfo.class));
        }
        return this.updateBatchById(blocks,5);
    }

    @Override
    public List blockEles(String blockId) {
        QueryWrapper<BlockBodyEle> query = new QueryWrapper();
        query.lambda().eq(BlockBodyEle::getPid,blockId)
                .orderByAsc(BlockBodyEle::getOrderNum)
                .orderByDesc(BlockBodyEle::getUpdatedAt);
        return blockBodyEleDao.selectList(query);
    }

    @Override
    public BlockInfo loadBlockEles(BlockInfo blockInfo) {
        blockInfo.setBodys(blockEles(blockInfo.getId()));
        if (ObjectUtils.isEmpty(blockInfo.getBodys())) return blockInfo;
        for (BlockBodyEle ele : blockInfo.getBodys()){
            try {
                ele.setParams(mapper.readValue(ele.getParamsPayload(), eleParamType));
            }
            catch (Exception e) {
                e.printStackTrace();
//                ele.setParams(List.of(ele.getParamsPayload()));
            }
        }
        return blockInfo;
    }
//
//    @Override
//    public List selectList(LinkedHashMap<String, Object> baseMap) {
//        Map paramMap = cn.zhxu.bs.util.MapUtils.builder(baseMap)
//                .orderBy(BlockInfoVo::getOrderNum).asc()
//                .orderBy(BlockInfoVo::getUpdatedAt).desc().build();
//        return mapSearcher.searchList(BlockInfoVo.class,paramMap);
//    }
//
    @Override
    public List listByPId(String pid) {
        QueryWrapper<BlockInfo> query = new QueryWrapper();
        query.lambda().eq(BlockInfo::getPid,pid)
                .orderByAsc(BlockInfo::getOrderNum)
                .orderByDesc(BlockInfo::getUpdatedAt);
        return list(query);
    }
}
